package com.ruoyi.system.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.web.config.ServerConfig;
import com.ruoyi.system.commons.utils.JsonValidationUtils;
import com.ruoyi.system.domain.ShotModel;
import com.ruoyi.system.domain.SysSourceRegistry;
import com.ruoyi.system.domain.dto.DeleteDto;
import com.ruoyi.system.domain.dto.QueryRegistryDto;
import com.ruoyi.system.domain.dto.ToolJsonDto;
import com.ruoyi.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.yaml.snakeyaml.Yaml;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 外部资源工具注册Controller
 * 
 * @author metaee
 * @date 2023-12-14
 */
@Slf4j
@RestController
@RequestMapping("/registry")
public class SysSourceRegistryController extends BaseController
{
    @Autowired
    private ISysSourceRegistryService sysSourceRegistryService;

    @Autowired
    private ShotService shotService;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private PromptService promptService;

    /**
     * 查询外部资源工具注册列表
     */
    @PostMapping("/list")
    public AjaxResult list(@RequestBody QueryRegistryDto queryRegistryDto)
    {
        if (queryRegistryDto.getPage() == null || queryRegistryDto.getPage() == 0){
            queryRegistryDto.setPage(1L);
        }
        if (queryRegistryDto.getSize() == null || queryRegistryDto.getSize() == 0){
            queryRegistryDto.setSize(10L);
        }

        Page<SysSourceRegistry> list = sysSourceRegistryService.selectSysSourceRegistryPage(queryRegistryDto);
        for (SysSourceRegistry sysSourceRegistry : list.getRecords()) {
            int statusCode = getServiceStatusCode(sysSourceRegistry.getId());
            sysSourceRegistry.setStatusCode(statusCode);
        }
        return success(list);
    }

    /**
     * 获取外部资源工具注册详细信息
     */
    @PostMapping(value = "/getInfo/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return success(sysSourceRegistryService.selectSysSourceRegistryById(id));
    }

    @PostMapping("/update")
    public R update(@RequestBody SysSourceRegistry sysSourceRegistry){
        if (sysSourceRegistry.getId() == null){
            return R.fail("必须提供要修改的tool的id");
        }

        sysSourceRegistry.setGmtModified(new Date());
        boolean res = sysSourceRegistryService.updateById(sysSourceRegistry);
        if (res){
            return R.ok(null,"修改成功！");
        }else {
            return R.fail("修改失败！");
        }
    }


    /**
     * 新增外部资源工具注册
     */
    @Log(title = "外部资源工具注册", businessType = BusinessType.INSERT)
    @PostMapping(value = "/add", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public AjaxResult add(@RequestParam("files") MultipartFile[] files, @RequestParam(value = "tools", required = false) String tools) throws IOException {
        if (files.length != 2) {
            return error("文件数量不符合要求");
        }

        List<String> urls = new ArrayList<String>();
        List<String> fileNames = new ArrayList<String>();
        List<String> newFileNames = new ArrayList<String>();
        List<String> originalFilenames = new ArrayList<String>();
        List<String> absFileName = new ArrayList<String>();

        boolean hasJson = false;
        boolean hasYaml = false;
        for (MultipartFile file : files) {
            String originalFilename = file.getOriginalFilename();
            if (originalFilename.endsWith(".json") || originalFilename.endsWith(".yaml")) {
                if (originalFilename.endsWith(".json")) {
                    hasJson = true;
                }
                if (originalFilename.endsWith(".yaml")) {
                    hasYaml = true;
                }

                String newFileName = FileUploadUtils.extractFilename(file);
                String url = serverConfig.getUrl() + Constants.RESOURCE_PREFIX + "/" + newFileName;
                String absPath = FileUploadUtils.getAbsoluteFile(RuoYiConfig.getProfile(), newFileName).getAbsolutePath();

                file.transferTo(Paths.get(absPath));

                urls.add(url);
                fileNames.add(newFileName);
                newFileNames.add(FileUtils.getName(newFileName));
                originalFilenames.add(file.getOriginalFilename());
                absFileName.add(absPath);
            }
        }
        if (!hasJson) {
            return error("错误！缺少json文件");
        }
        if (!hasYaml) {
            return error("错误！缺少yaml文件");
        }

        String jsonFileUrl = null;
        String yamlFileUrl = null;
        for (int i = 0; i < urls.size(); i++) {
            String url = urls.get(i);
            if (url.contains(".yaml")) {
                yamlFileUrl = url;
            } else if (url.contains(".json")) {
                jsonFileUrl = url;
            }
        }

        String serviceUrl = null;
        String resourceName = null;
        String description = null;
        String label = null;
        JSONArray shotsArray = null;
        for (int i = 0; i < absFileName.size(); i++) {
            String filename = absFileName.get(i);
            if (filename.endsWith(".json")) {
                String jsonStr = new String(Files.readAllBytes(Paths.get(filename)));
                JSONObject jsonObject = JSON.parseObject(jsonStr);
                // 模型基本信息
                resourceName = jsonObject.containsKey("name_for_human") ? jsonObject.getString("name_for_human") : "";
                description = jsonObject.containsKey("description_for_human") ? jsonObject.getString("description_for_human") : "";
                label = jsonObject.containsKey("label") ? jsonObject.getString("label") : null;

                // 模型shot信息
                shotsArray = jsonObject.containsKey("shots") ? jsonObject.getJSONArray("shots") : null;
            }
            if (filename.endsWith(".yaml")) {
                Yaml yaml = new Yaml();
                BufferedReader br = new BufferedReader(new FileReader(filename));
                LinkedHashMap<String, Object> objectMap = yaml.load(br);

                ArrayList<Object> serversList = (ArrayList<Object>) objectMap.get("servers");
                if (serversList.size() > 0) {
                    LinkedHashMap<String, Object> urlMap = (LinkedHashMap<String, Object>) serversList.get(0);
                    String url = (String) urlMap.get("url");

                    if (url != null && !url.isEmpty()) {
                        serviceUrl = url;
                    }
                }
            }
        }

        int ret = 0;
        SysSourceRegistry sysSR = sysSourceRegistryService.selectExistSysSourceRegistryByName(resourceName);
        if (sysSR != null) {
            for (int j = 0; j < absFileName.size(); j++) {
                Files.delete(Paths.get(absFileName.get(j)));
            }
            return error("该服务已经存在");
        } else {
            SysSourceRegistry sysSourceRegistry = new SysSourceRegistry();
            sysSourceRegistry.setResourceName(resourceName);
            sysSourceRegistry.setDescription(description);
            sysSourceRegistry.setJsonFileUrl(jsonFileUrl);
            sysSourceRegistry.setYamlFileUrl(yamlFileUrl);
            sysSourceRegistry.setServiceUrl(serviceUrl);
            sysSourceRegistry.setCreator(SecurityUtils.getUserId());
            sysSourceRegistry.setGmtCreated(new Date());
            sysSourceRegistry.setIsDeleted(0L);
            sysSourceRegistry.setLabel(label);
            sysSourceRegistry.setTools(tools);
            ret = sysSourceRegistryService.insertSysSourceRegistry(sysSourceRegistry);
        }

        if (shotsArray != null && ret > 0) {
            for (int j = 0; j < shotsArray.size(); j++) {
                JSONObject shotItemJson = shotsArray.getJSONObject(j);
                String queryInput = shotItemJson.getString("query_input");
                String expectedOutput = shotItemJson.getString("expected_output");

                ShotModel shotModel = new ShotModel();
                shotModel.setStToolsName(resourceName);
                shotModel.setStQueryInput(queryInput);
                shotModel.setStExpectedOutput(expectedOutput);
                shotModel.setGmtCreated(DateUtils.getTime());
                shotModel.setCreator(SecurityUtils.getUserId());
                shotModel.setIsDeleted(0);

                shotService.save(shotModel);
            }
        }

        return toAjax(ret);
    }

//    /**
//     * 修改外部资源工具注册
//     */
//    @Log(title = "外部资源工具注册", businessType = BusinessType.UPDATE)
//    @PutMapping
//    public AjaxResult edit(@RequestBody SysSourceRegistry sysSourceRegistry)
//    {
//        return toAjax(sysSourceRegistryService.updateSysSourceRegistry(sysSourceRegistry));
//    }

//    /**
//     * 删除外部资源工具注册
//     */
//    @Log(title = "外部资源工具注册", businessType = BusinessType.DELETE)
//	@DeleteMapping("/remove/{ids}")
//    public AjaxResult remove(@PathVariable Long[] ids)
//    {
//        return toAjax(sysSourceRegistryService.deleteSysSourceRegistryByIds(ids));
//    }




    @Log(title = "外部资源工具注册", businessType = BusinessType.INSERT)
    @PostMapping(value = "/register", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public AjaxResult registerTool(@RequestParam("file") MultipartFile file , @RequestParam(value = "tools", required = false) String tools) throws IOException {
        /**@Description: todo:这边注册的逻辑改变了，这边还没有做修改
         * @param [file]
         * @return AjaxResult
         */

        if (file == null) {
            return AjaxResult.error("请上传文件！");
        }

        String fileOriginalName = file.getOriginalFilename();

        if (!fileOriginalName.endsWith(".json")) {
            return AjaxResult.error("上传失败！请上传json文件！");
        }

        String fileName = FileUploadUtils.extractFilename(file);
        log.info("new file name:" + fileName);

        //将文件传输到absPath 当前服务器路径下 /profile文件夹下 ，这个要确定一下路径到底是怎么个路径
        String url = serverConfig.getUrl() + Constants.RESOURCE_PREFIX + "/" + fileName;
        String absPath = FileUploadUtils.getAbsoluteFile(RuoYiConfig.getProfile(), fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));//存储文件

        //格式校验
        String jsonStr = new String(Files.readAllBytes(Paths.get(absPath)));
        boolean isValid = JsonValidationUtils.schemaValidation(JsonValidationUtils.REGISTRY_JSON_SCHEMA, jsonStr);
        if (!isValid) {
            return AjaxResult.error("上传失败！JSON文件校验失败！");
        }
        JSONObject jsonObject = JSON.parseObject(jsonStr);

        //注册到数据库
        SysSourceRegistry toolModel = new SysSourceRegistry();
        toolModel.setCreator(SecurityUtils.getUserId());
        toolModel.setGmtCreated(new Date());
        toolModel.setGmtModified(new Date());
        toolModel.setIsDeleted(0L);
//        工具集名称
        toolModel.setTools(tools);

        String toolName = jsonObject.getString("tool_name");

        LambdaQueryWrapper<SysSourceRegistry> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysSourceRegistry::getResourceName, toolName);
        queryWrapper.eq(SysSourceRegistry::getIsDeleted,0L);
        queryWrapper.eq(SysSourceRegistry::getTools,tools);
        List<SysSourceRegistry> dataDetectors = sysSourceRegistryService.list(queryWrapper);
        if (dataDetectors.size()>1){
            return AjaxResult.error("工具名不允许重复！");
        }

        String des = jsonObject.getString("description");
        String serviceUrl = jsonObject.getString("base_url") + jsonObject.getString("path");
        toolModel.setResourceName(toolName);
        toolModel.setDescription(des);
        toolModel.setServiceUrl(serviceUrl);
        toolModel.setJsonFileUrl(url);
        //tool_prompt
        String toolPrompt = jsonObject.containsKey("prompt") ? jsonObject.getString("prompt") : "";
        // 拼接工具的prompt
        if (toolPrompt.equals("")) {
            String content = new String(file.getBytes(), StandardCharsets.UTF_8);
            ToolJsonDto tool = JSON.parseObject(content,ToolJsonDto.class);
            toolPrompt = promptService.assemblePrompt(tool);
        }
        toolModel.setToolPrompt(toolPrompt);
        sysSourceRegistryService.save(toolModel);

        //动态拼接
        String toolKitName = toolModel.getTools();
        String toolKitUpdatePrompt = promptService.assembleIRPrompt(toolKitName);
        sysSourceRegistryService.updateToolKitPrompt(toolKitName, toolKitUpdatePrompt);

        //tool_shot!!!
        JSONArray shotsArray = jsonObject.containsKey("shots") ? jsonObject.getJSONArray("shots") : null;
        //shots 落库
        if (shotsArray != null) {
            for (int j = 0; j < shotsArray.size(); j++) {
                JSONObject shotItemJson = shotsArray.getJSONObject(j);

                String queryInput = shotItemJson.getString("query_input");
                String expectedOutput = shotItemJson.getString("expected_output");

                ShotModel shotModel = new ShotModel();
                shotModel.setStToolsName(toolName);
                shotModel.setStQueryInput(queryInput);
                shotModel.setStExpectedOutput(expectedOutput);
                shotModel.setGmtCreated(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                shotModel.setGmtModified(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                shotModel.setCreator(SecurityUtils.getUserId());
                shotModel.setIsDeleted(0);
                shotModel.setIsToolkit(0);

                shotService.save(shotModel);
            }
        }
        return AjaxResult.success("上传成功！");
    }
    /**
     * 逻辑删除外部资源工具注册
     * @param deleteDto
     * @return
     */
    @PostMapping("/logic-delete")
    public AjaxResult logicDelete(@RequestBody DeleteDto deleteDto) {
        if (deleteDto.getId() == null) {
            return error("工具id不能为空");
        }

        SysSourceRegistry sysSourceRegistry = sysSourceRegistryService.selectSysSourceRegistryById(deleteDto.getId());

        UpdateWrapper<ShotModel> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("st_tools_name", sysSourceRegistry.getResourceName());
        updateWrapper.set("is_deleted", 1);
        shotService.update(updateWrapper);

        sysSourceRegistry.setIsDeleted(1L);

        //动态拼接 工具集的prompt 工具链
        String toolKitName = sysSourceRegistry.getTools();
        String toolKitUpdatePrompt = promptService.assembleIRPrompt(toolKitName);
        sysSourceRegistryService.updateToolKitPrompt(toolKitName, toolKitUpdatePrompt);

        return toAjax(sysSourceRegistryService.updateSysSourceRegistry(sysSourceRegistry));
    }

    @PostMapping("/check-service")
    public AjaxResult checkService(@RequestParam(value = "id", required = true) Long id) throws IOException {
        if (id == null) {
            return error("工具id不能为空");
        }
        JSONObject retJson = new JSONObject();
        retJson.put("status_code", getServiceStatusCode(id));
        return success(retJson);
    }

    private int getServiceStatusCode(Long id) {
        /**@Description: 从数据库的service_url字段读取测试链接的url,并测试连接
         * @param [id]
         * @return int
         */
        try {
            int statusCode = -1;
            SysSourceRegistry sysSourceRegistry = sysSourceRegistryService.selectSysSourceRegistryById(id);
            if (sysSourceRegistry != null) {
                String url = sysSourceRegistry.getServiceUrl();
                if (!url.isEmpty()) {
                    RestTemplate restTemplate = new RestTemplate();
                    ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
                    statusCode = response.getStatusCodeValue();
                }
            }
            return statusCode;
        }   catch (HttpClientErrorException | HttpServerErrorException e) {
            e.printStackTrace();
            int rawStatusCode = e.getRawStatusCode();
            return rawStatusCode;
        }  catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
}
